package fr.SDroid.Calcul;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;

import fr.SDroid.Graph.Graph;
import fr.SDroid.Graph.Ligne;
import fr.SDroid.Graph.Station;

public class Dijkstra implements Serializable{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Graph _graph;
	private Station _debut;
	private Station _fin;
	private Integer _poids;
	private Integer _poidsCorresp;
	private Boolean _end;
	private ArrayList<Station> stationParcouru;
	private ArrayList<ArrayList<HashMap<Ligne, ArrayList<Station>>>> _result;
	
	public Dijkstra(Graph g) {
		_graph = g;
		_debut = g.getDepart();
		_fin = g.getArrive();
		_poids = 2;
		_poidsCorresp = 2;
		_result = new ArrayList<ArrayList<HashMap<Ligne,ArrayList<Station>>>>();
		
		initialisation(_debut);
		
	}
	
	private void initialisation(Station debut) {
		for(int i = 0; i < _graph.getLignes().size(); i++) {
			Ligne li = _graph.getLignes().get(i);
			for(int j = 0; j < li.getListStation().size(); j++) {
				li.getListStation().get(j).setDistance(Integer.MAX_VALUE);
				li.getListStation().get(j).setEnd(false);
				li.getListStation().get(j).init();
			}
		}
		_debut.setDistance(0);
	}
	
	public void setDebut(Station debut) {
		_debut = debut;
	}
	
	public void setFin(Station fin) {
		_fin = fin;
	}
	
	public Station getFin() {
		return _fin;
	}
	
	public Station getDebut(){
		return _debut;
	}
	
	public void lessCoresp() {
		_poidsCorresp = 10;
	}
	
	public void startCalcul() {
		start();
		calcResult();
		initialisation(_debut);
		_poidsCorresp = 200;
		
		start();
		
		calcResult();
	}
	
	public void start() {
		Station stat = _debut;
		while(stat != null) {
			stationParcouru = new ArrayList<Station>();
			calcMin(stat);
			stat = getMin(_debut);
		}
	}
	
	private void calcMin(Station station) {
		station.setEnd(true);
		for(int i = 0; i < station.getFils().size(); i++) {
			if(station.getFils().get(i).getDistance() > station.getDistance() + _poids) {
				station.getFils().get(i).setDistance(station.getDistance() + _poids, station);
			}
		}
		for(int i = 0; i < station.getCoresp().size(); i++) {
			if(station.getCoresp().get(i).getDistance() > station.getDistance() + _poidsCorresp) {
				station.getCoresp().get(i).setDistance(station.getDistance() + _poidsCorresp, station);
			}
		}
	}
	
	private Station getMin(Station station) {
		if(!stationParcouru.contains(station)) {
			stationParcouru.add(station);
			Station tempMin = null;
			if(!station.getEnd())
				tempMin = station;
			for(int i = 0; i < station.getFils().size(); i++) {
				Station temp = getMin(station.getFils().get(i));
				if(tempMin != null && temp != null && !temp.getEnd() && tempMin.getDistance() > temp.getDistance())
					tempMin = temp;
				else {
					if(tempMin == null && temp != null && !temp.getEnd() )
						tempMin = temp;
				}
			}
			for(int i = 0; i < station.getCoresp().size(); i++) {
				Station temp = getMin(station.getCoresp().get(i));
				if(tempMin != null && temp != null && !temp.getEnd() && tempMin.getDistance() > temp.getDistance())
					tempMin = temp;
				else {
					if(tempMin == null &&temp != null && !temp.getEnd() )
						tempMin = temp;
				}
			}
			return tempMin;
		}
		return null;
	}
	
	public ArrayList<HashMap<Ligne, ArrayList<Station>>> getResultCoresp() {
		return _result.get(1);
	}
	public ArrayList<HashMap<Ligne, ArrayList<Station>>> getResultTemp() {
		return _result.get(0);
	}
	
	public ArrayList<ArrayList<HashMap<Ligne, ArrayList<Station>>>> calcResult() {
		
		ArrayList<HashMap<Ligne, ArrayList<Station>>> currentResult = new ArrayList<HashMap<Ligne,ArrayList<Station>>>();		
		
		// on supprime la premiere correspondance si elle existe
		if(_fin.getFrom() != null && (_fin.getName().equals(_fin.getFrom().getName()))) {
			_fin = _fin.getFrom();
		}
		
		Station currentStation = _fin;
		Ligne currentLigne = currentStation.getLigne();
		
		HashMap<Ligne, ArrayList<Station>> map = new HashMap<Ligne, ArrayList<Station>>();
		ArrayList<Station> listStation = new ArrayList<Station>();
		listStation.add(currentStation);
		map.put(currentLigne, listStation);
		
		

		while (currentStation.getFrom() != null) {
			currentStation = currentStation.getFrom();
			if(currentStation.getLigne() == currentLigne) {
				listStation.add(currentStation);
			}else {
				// on insere la ligne actuel
				currentResult.add(map);
				// on cree une nouvelle ligne dans les resultats.
				currentLigne = currentStation.getLigne();
				
				map = new HashMap<Ligne, ArrayList<Station>>();
				listStation = new ArrayList<Station>();
				listStation.add(currentStation);
				map.put(currentLigne, listStation);
			}
			
			if(currentStation.getFrom() != null && currentStation.getFrom().getFrom() == null && currentStation.getName().equals(currentStation.getFrom().getName())) {
				currentStation.setDistance(0);
			}
			
		}
		
		currentResult.add(map);
		
		_result.add(currentResult);
		
		
		
/*		HashMap<String, ArrayList<Station>> result = new HashMap<String, ArrayList<Station>>();
		
		ArrayList<Station> sta = new ArrayList<Station>();
		Station from = _fin;
		int nbCore = 0;
		while(from != null) {
			sta.add(from);
			from = from.getFrom();
		}
		if(sta.size() > 1) {
			if(sta.get(0).getName().equals(sta.get(1).getName())) {
				sta.remove(0);
			}
		}
		if(sta.size() > 2) {
			if(sta.get(sta.size()-1).getName().equals(sta.get(sta.size()-2).getName())) {
				sta.remove(sta.size()-1);
			}
		}
		int temp = 2 * (sta.size()-1);
		for(int i = 0; i < sta.size()-1; i++) {
			if(sta.get(i).getName().equals(sta.get(i+1).getName()))
				nbCore++;
		}
		
		result.put(temp+" minutes, "+nbCore+" corespondance", sta);
		
		
		result.put("40 minutes, 6 corespondance", new ArrayList<Station>());*/
		
		return _result;
	}
	
	
	
	
	
	

}
